package cn.hiapi.shop.api;

import cn.hiapi.basic.ResponseEntity;
import cn.hiapi.basic.controller.BasicController;
import cn.hiapi.basic.jpa.pageable.QueryWrapper;
import cn.hiapi.basic.security.TokenGet;
import cn.hiapi.interfaces.DispatchContext;
import cn.hiapi.shop.service.shop.ShopLinkUserService;
import cn.hiapi.shop.vo.ChartItem;
import cn.hiapi.shopkeeper.entity.order.ActivityOrder;
import cn.hiapi.shopkeeper.service.order.ActivityOrderService;
import cn.hiapi.shopkeeper.service.shopkeeper.ShopUserService;
import cn.hiapi.utils.DateUtils;
import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author AdinZ
 * @date 2023/2/8 14:24
 */
@RestController
@RequestMapping("/shop/data-view")
public class DataViewController extends BasicController {

    private final DispatchContext dispatchContext;

    public DataViewController(DispatchContext dispatchContext) {
        this.dispatchContext = dispatchContext;
    }

    private static final String[] WEEK_NAMES = new String[]{"星期", "周一", "周二", "周三", "周四", "周五", "周六", "周日"};

    @GetMapping("")
    public ResponseEntity dataView(@RequestParam("shopId") long shopId,
                                   @RequestParam("action") String action,
                                   @RequestParam(value = "date", required = false) String date) {
        this.dispatchContext.getServiceOne(ShopLinkUserService.class).verifyShop(TokenGet.get().getFid(), shopId);

        try {
            switch (action) {
                case "today":
                    return this.dataDayTotal(shopId, DateUtils.format(DateUtils.FORMAT_YYYY_MM_DD));
                case "this-week":
                    return this.dataWeekTotal(shopId, DateUtils.format(DateUtils.FORMAT_YYYY_MM_DD));
                case "this-month":
                    return this.dataMonthTotal(shopId, DateUtils.format(DateUtils.FORMAT_YYYY_MM));
                case "day":
                    return this.dataDayTotal(shopId, date);
                case "month":
                    return this.dataMonthTotal(shopId, date);
                case "year":
                    break;
                default:
                    return toError("格式类型错误");
            }
        } catch (ParseException e) {
            return toError("日期格式错误");
        }
        return null;
    }

    private ResponseEntity dataMonthTotal(long shopId, String month) throws ParseException {
        JSONObject data = new JSONObject();
        Date date = DateUtils.parse(month, DateUtils.FORMAT_YYYY_MM);
        Date todayStart = DateUtils.todayStart(DateUtils.getMonthStart(date));
        Date todayEnd = DateUtils.todayEnd(DateUtils.getMonthEnd(date));

        this.toThisData(data, shopId, todayStart, todayEnd, "month");


        todayStart = DateUtils.todayStart(DateUtils.getMonthStart(date, -1));
        todayEnd = DateUtils.todayEnd(DateUtils.getMonthEnd(date, -1));

        this.toPreviousData(data, shopId, todayStart, todayEnd, "month");
        return toSuccess(data);
    }

    private ResponseEntity dataWeekTotal(long shopId, String day) throws ParseException {
        JSONObject data = new JSONObject();
        Date date = DateUtils.parse(day, DateUtils.FORMAT_YYYY_MM_DD);
        Date todayStart = DateUtils.todayStart(DateUtils.getWeekStart(date));
        Date todayEnd = DateUtils.todayEnd(DateUtils.getWeekEnd(date));

        this.toThisData(data, shopId, todayStart, todayEnd, "week");

        date = DateUtils.addDay(date, -7);
        todayStart = DateUtils.todayStart(DateUtils.getWeekStart(date));
        todayEnd = DateUtils.todayEnd(DateUtils.getWeekEnd(date));
        this.toPreviousData(data, shopId, todayStart, todayEnd, "week");
        return toSuccess(data);
    }


    private ResponseEntity dataDayTotal(long shopId, String day) throws ParseException {
        JSONObject data = new JSONObject();
        Date date = DateUtils.parse(day, DateUtils.FORMAT_YYYY_MM_DD);
        Date todayStart = DateUtils.todayStart(date);
        Date todayEnd = DateUtils.todayEnd(date);
        this.toThisData(data, shopId, todayStart, todayEnd, "day");

        date = DateUtils.addDay(date, -1);
        todayStart = DateUtils.todayStart(date);
        todayEnd = DateUtils.todayEnd(date);
        this.toPreviousData(data, shopId, todayStart, todayEnd, "day");

        return toSuccess(data);
    }


    private void toThisData(JSONObject data, long shopId, Date todayStart, Date todayEnd, String action) {
        data.put("totalMoney", this.dispatchContext.getServiceOne(ActivityOrderService.class).totalMoney(shopId, todayStart.getTime(), todayEnd.getTime()));
        data.put("totalCount", this.dispatchContext.getServiceOne(ActivityOrderService.class).totalCount(shopId, todayStart.getTime(), todayEnd.getTime()));
        data.put("payUser", this.dispatchContext.getServiceOne(ActivityOrderService.class).totalBuyUser(shopId, todayStart.getTime(), todayEnd.getTime()));
        data.put("newUser", this.dispatchContext.getServiceOne(ShopUserService.class).totalCount(shopId, todayStart.getTime(), todayEnd.getTime()));
        List<ActivityOrder> list = this.dispatchContext.getServiceOne(ActivityOrderService.class).findList(new QueryWrapper().eq("shopId", shopId)
                .eq("statusType", 1).between("created", todayStart.getTime(), todayEnd.getTime()));
        data.put("charts", this.orderToChat(action, list, todayStart));
    }

    private void toPreviousData(JSONObject data, long shopId, Date todayStart, Date todayEnd, String action) {
        data.put("previousMoney", this.dispatchContext.getServiceOne(ActivityOrderService.class).totalMoney(shopId, todayStart.getTime(), todayEnd.getTime()));
        data.put("previousCount", this.dispatchContext.getServiceOne(ActivityOrderService.class).totalCount(shopId, todayStart.getTime(), todayEnd.getTime()));
        data.put("previousPayUser", this.dispatchContext.getServiceOne(ActivityOrderService.class).totalBuyUser(shopId, todayStart.getTime(), todayEnd.getTime()));
        data.put("previousNewUser", this.dispatchContext.getServiceOne(ShopUserService.class).totalCount(shopId, todayStart.getTime(), todayEnd.getTime()));
        List<ActivityOrder> list = this.dispatchContext.getServiceOne(ActivityOrderService.class).findList(new QueryWrapper().eq("shopId", shopId)
                .eq("statusType", 1).between("created", todayStart.getTime(), todayEnd.getTime()));
        data.put("previousCharts", this.orderToChat(action, list, todayStart));
    }


    private List<ChartItem> orderToChat(String action, List<ActivityOrder> list, Date date) {
        List<String> dates = new ArrayList<>();
        dates.addAll(this.toChatNames(action, date));


        List<ChatTemData> collect = list.stream().map(e -> {
            ChatTemData temData = new ChatTemData();
            if (StringUtils.equals(action, "day")) {
                temData.setDate(DateUtils.format(e.getCreated(), DateUtils.FORMAT_YYYY_MM_DD));
            } else if (StringUtils.equals(action, "week")) {
                int week = DateUtils.getWeekOfDate(e.getCreated());
                temData.setDate(WEEK_NAMES[week]);
            } else if (StringUtils.equals(action, "month")) {
                int day = DateUtils.getDay(new Date(e.getCreated()));
                temData.setDate(String.valueOf(day));
            }
            temData.setMoney(e.getPayment());
            return temData;
        }).collect(Collectors.toList());
        return dates.stream().map(e -> {
            ChartItem item = new ChartItem();
            item.setLabel(e);
            Optional<BigDecimal> optional = collect.stream().filter(x -> StringUtils.equals(x.getDate(), e)).map(ChatTemData::getMoney).reduce(BigDecimal::add);
            item.setValue(optional.isPresent() ? optional.get() : BigDecimal.ZERO);
            return item;
        }).collect(Collectors.toList());
    }

    private static Collection<String> toChatNames(String action, Date date) {
        List<String> result = new ArrayList<>();
        if (StringUtils.equals(action, "day")) {
            long todayStart = DateUtils.todayStart(date).getTime();
            for (int i = 0; i < 24; i++) {
                long hour = DateUtils.addHour(todayStart, i);
                result.add(DateUtils.format(hour, DateUtils.FORMAT_YYYY_MM_DD_HH));
            }
        } else if (StringUtils.equals(action, "week")) {
            Date weekStart = DateUtils.getWeekStart(date);
            for (int i = 0; i < 7; i++) {
                int week = DateUtils.getWeekOfDate(DateUtils.addDay(weekStart, i));
                result.add(WEEK_NAMES[week]);
            }
        } else if (StringUtils.equals(action, "month")) {
            Date monthStart = DateUtils.getMonthStart(date);
            int count = DateUtils.getMonthDayCount(monthStart);
            for (int i = 0; i < count; i++) {
                int day = DateUtils.getDay(DateUtils.addDay(monthStart, i));
                result.add(String.valueOf(day));
            }
        }
        return result;
    }

    @Setter
    @Getter
    private class ChatTemData {
        private String date;
        private BigDecimal money;


    }


}
